#include "nw_definitions.h"


static void TR_process_packet(PACKET *);

 
/*
 * ROUTING BEGIN
 * ---------------------------------------------------------------------------------------------------------------------
 */


//updates the cost table and returns the new cost if changes to the ROUTING table were made
//updates the cost table and returns the new cost if changes to the ROUTING table were made
static int modify_cost( char* destination, int cost, int link)
{
	/*
	 * ***************************** COST COMPUTATION BEGIN
	 * 
	 */ 

	float link_bw =		linkinfo[link].bandwidth;
	float link_load = 	queue_nitems(out_link_data(link).buffer) + 1; 		//lazy max(buffer_entries, 1)   
//	float link_cost=	link_load/link_bw + link_pd; 	
	float link_cost=	1.f/link_bw + link_load;							//temp static, depends on how big our buffers will be		 		                                                                                                                     
	cost +=				link_cost; //rounding to int


	/*
	 * 
	 ******************************* COST COMPUTATION END
	 */ 
	 

	
	hashtable_add(link_cost_table(link),destination, &cost, sizeof(int));	//adding the computed cost to the (dest,cost) table of the corr. linkk
	

	//checking if rt needs to be updated
	int* ptr_linkno = NULL;
	size_t len;
	ptr_linkno = hashtable_find(ht_destinations,destination, &len);			//might be that dest. is in a link cost table, but not yet in the rt
	
	int* curr_cost = NULL;	
	
	//printf("link ptr:%d\n", ptr_linkno);
	if(ptr_linkno) { //we have an entry for this destination, need to find out the cost
		curr_cost = hashtable_find(link_cost_table(*ptr_linkno),destination, &len);
	} else {
		vector_append(a_avail_destinations, destination, 2* sizeof(char));	//destination became available now
	}

	
	if(curr_cost == NULL || *curr_cost > cost) {	 						//new route is cheaper
		hashtable_add(ht_destinations, destination, &link, sizeof(int));	//update the routing table
		return cost;
	}
	
	return -1; //no changes to routing table were made; i.e., new cost >= current cost
}

void NW_receive_disc_packet(PACKET* pkt,int link) 
{	
	
	unsigned char destination = pkt->msg.data[0]; 							//node address which reachability cost has changed
	unsigned char cost = pkt->msg.data[1];									//new cost to it from the sending node
	char ptr_destination[2] = {(char)destination, 0 };
	
	if(destination == nodeinfo.address)
	{
		return;
	}
	
	int new_cost = modify_cost(ptr_destination, cost, link);
	
	if(new_cost >= 0) 
	{
		NW_create_disc_pkt(destination, new_cost, link, pkt->msg.data[2]);
	} else
	{
	};
}	
/*
 * ROUTING END
 * ---------------------------------------------------------------------------------------------------------------------
 */



void NW_receive_packet(PACKET* pkt,int link)
{	
	//first error check
	if(pkt->src == pkt->dest && pkt->len == 3) {//discovery pkt received
		NW_receive_disc_packet(pkt,link);
	}
	else { //no dicovery packet: either packet to this node or to an other one
		
		if(pkt->dest == nodeinfo.address) { //this is the destination node
				TR_process_packet(pkt); //packet processed by this node
				//CHECK(CNET_write_application(&(pkt->msg), &(pkt->len)));
		} else { //packet has to be processed according to the routing table
			if(pkt->crc_head == head_crc(pkt))
			{
				NW_route_packet(pkt);
			}
		}
	}
	
}
 
